﻿using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using System.Xml.Linq;
using MDCAdminTool.Configuration;
using Microsoft.Windows.Controls.Ribbon;
using System.Windows.Controls;
using E4D.AppFabric.Entities;

using System.Collections;
using WinInterop = System.Windows.Interop;
using System.Runtime.InteropServices;

namespace MDCAdminTool
{
    public partial class MainWindow : RibbonWindow
    {
        private object _SelectedItem;

        public object SelectedItem
        {
            get { return _SelectedItem; }
        }

        public MainWindow()
        {
            InitializeComponent();
        }

        private void ClustersTreeView_SelectedItemChanged( object sender , RoutedPropertyChangedEventArgs<object> e )
        {
            _SelectedItem    = e.NewValue;
            DataContext      = _SelectedItem;

            SetRibbonTab();
        }

        private void SetRibbonTab()
        {
            if ( SelectedItem is CacheCluster ||
                SelectedItem is CacheGroup ||
                SelectedItem is CacheGroupHA ||
                SelectedItem is HostGroup )
            {
                ribbon.SelectedTab = rtCluster;
            }
            else if ( SelectedItem is CacheHost )
            {
                ribbon.SelectedTab = rtHost;
            }
            else if ( SelectedItem is MdcCache )
            {
                ribbon.SelectedTab = rtCache;
            }
            else if ( SelectedItem is CacheRegion )
            {
                ribbon.SelectedTab = rtCache;
            }

            foreach (var tab in ribbon.Tabs)
            {
                tab.Visibility = tab == ribbon.SelectedTab ? Visibility.Visible : Visibility.Collapsed;
            }
        }

        private void ClustersTreeView_MouseDoubleClick( object sender , MouseButtonEventArgs e )
        {
            App.NewTab();
        }

        internal static void ReLoadClusterTreeView()
        {
            var tv = Application.Current.Properties["ClustersTreeView"] as TreeView;
            var clusters = Application.Current.Properties["Clusters"] as Clusters;

            if (tv != null)
                tv.Dispatcher.Invoke(
                        new Action( () => { tv.DataContext = null;
                                            tv.DataContext = clusters; } )
                    );
        }

        private void RibbonWindow_Loaded( object sender , RoutedEventArgs e )
        {
            App.Tree        = ClustersTreeView;
            App.Output      = lbOutput;
            App.TabControl  = tabControl;
            App.ProgressBar = powerShellProgressBar;

            //systemRequirementsCheck.Visibility = Visibility.Collapsed;
            //systemRequirementsCheck.BeginRun();

            systemRequirementsCheck_EndCheck(this , EventArgs.Empty);
            
            this.SetRibbonTab();
        }

        private void EndLoadCacheCluster(IAsyncResult ar)
        {
            try
            {
                var func = ar.AsyncState as Action;
                if (func != null)
                    func.EndInvoke(ar);
            }
            catch (Exception exp)
            {
                using (System.Windows.Forms.Form topMostForm = new System.Windows.Forms.Form())
                {
                    topMostForm.TopMost = true;
                    System.Windows.Forms.MessageBox.Show(topMostForm, "Error loading cache cluster(s). Check the caching.config file.\n" + exp.Message, "Error", 
                        System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);              
                }                
            }

            ClustersTreeView.Dispatcher.Invoke(
                new Action(
                    () =>
                    {
                        Clusters clusters = Application.Current.Properties["Clusters"] as Clusters;
                        ClustersTreeView.DataContext = clusters;

                        //ClustersTreeView.SetBinding(TreeView.ItemsSourceProperty, string.Empty);

                        powerShellProgressBar.Stop();
                    }));
        }

        private void LoadCacheCluster()
        {
            var clusters = new Clusters {Logger = lbOutput};
            clusters.LoadFromConfiguration();

        	var watcher = new FileSystemWatcher(new DirectoryInfo(@".\").FullName);
			watcher.NotifyFilter = NotifyFilters.LastWrite;
			watcher.Filter = "*.config";
			
			//TODO: Uncomment this if you'd like to restart app on config change.
			//watcher.EnableRaisingEvents = true;


			watcher.Changed += OnConfigChanged; 
			App.Clusters = clusters;
        }

    	private Boolean _restartInitiated = false;
		void OnConfigChanged(object sender, FileSystemEventArgs e)
		{
			if ((new FileInfo(e.FullPath)).Name.ToLower() == "caching.config" && !_restartInitiated)
			{
				((ILogger) lbOutput).Add("Config changed");
				_restartInitiated = true;

				Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new ThreadStart(() => Application.Current.Shutdown(1)));
				System.Windows.Forms.Application.Restart();
				Application.Current.Shutdown();
			}
		}

    	private void systemRequirementsCheck_EndCheck( object sender , EventArgs e )
        {
            Action func = LoadCacheCluster;
            powerShellProgressBar.Start();
            func.BeginInvoke( EndLoadCacheCluster , func );
        }

        private void RibbonWindow_SourceInitialized(object sender, EventArgs e)
        {
            System.IntPtr handle = (new WinInterop.WindowInteropHelper(this)).Handle;
            WinInterop.HwndSource.FromHwnd(handle).AddHook(new WinInterop.HwndSourceHook(WindowProc));
        }

        private static System.IntPtr WindowProc(
              System.IntPtr hwnd,
              int msg,
              System.IntPtr wParam,
              System.IntPtr lParam,
              ref bool handled)
        {
            switch (msg)
            {
                case WinSysUtils.WM_GETMINMAXINFO:
                    WmGetMinMaxInfo(hwnd, lParam);
                    handled = true;
                    break;
            }

            return (System.IntPtr)0;
        }

        private static void WmGetMinMaxInfo(System.IntPtr hwnd, System.IntPtr lParam)
        {

            WinSysUtils.MINMAXINFO mmi = (WinSysUtils.MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(WinSysUtils.MINMAXINFO));

            // Adjust the maximized size and position to fit the work area of the correct monitor
            int MONITOR_DEFAULTTONEAREST = 0x00000002;
            System.IntPtr monitor = WinSysUtils.MonitorFromWindow(hwnd, MONITOR_DEFAULTTONEAREST);

            if (monitor != System.IntPtr.Zero)
            {

                WinSysUtils.MONITORINFO monitorInfo = new WinSysUtils.MONITORINFO();
                WinSysUtils.GetMonitorInfo(monitor, monitorInfo);
                WinSysUtils.RECT rcWorkArea = monitorInfo.rcWork;
                WinSysUtils.RECT rcMonitorArea = monitorInfo.rcMonitor;
                mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.left - rcMonitorArea.left);
                mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.top - rcMonitorArea.top);
                mmi.ptMaxSize.x = Math.Abs(rcWorkArea.right - rcWorkArea.left);
                mmi.ptMaxSize.y = Math.Abs(rcWorkArea.bottom - rcWorkArea.top);
            }

            Marshal.StructureToPtr(mmi, lParam, true);
        }

        //private void CommandBinding_CanExecute( object sender , CanExecuteRoutedEventArgs e )
        //{
        //    //if ( !systemRequirementsCheck.IsOk && !systemRequirementsCheck.IsRun)
        //        e.CanExecute = true;
        //}
        //private void CommandBinding_Executed( object sender , ExecutedRoutedEventArgs e )
        //{
        //    systemRequirementsCheck.BeginRun();
        //    systemRequirementsCheck.Visibility = Visibility.Visible;
        //}
    }
}
